#include "BeanMapper.h"
#include <QMetaProperty>
#include "private/sqloperator.h"
#include <QDebug>

using namespace DB;
static QMap<QString,QString> typeMapper =
{
    {"QString","TEXT"},
    {"int"    ,"INTEGER"},
    {"double" ,"REAL"},
    {"float"  ,"REAL"},
    {"bool"   ,"INTEGER"},


};


#define IS_PRIMARY_KEY(MetaProperty)    (! MetaProperty.isDesignable())
#define IS_NOT_NULL(MetaProperty)       (! MetaProperty.isScriptable())
#define IS_AUTO_UP(MetaProperty)        (! MetaProperty.isStored())
#define IS_ONLY_VAL(MetaProperty)       ( MetaProperty.isUser())

BeanMapper::BeanMapper()
{
    mp_SqlOperator = new  DB::SqlOperator();
}

BeanMapper::~BeanMapper()
{
    if(mp_SqlOperator)
    {
        mp_SqlOperator->close();
        delete mp_SqlOperator;
        mp_SqlOperator = nullptr;
    }
}

bool BeanMapper::openDB(const DataBaseConfig &config)
{

    if(mp_SqlOperator)
    {
      return  mp_SqlOperator->open(config);
    }
    return false;
}
const QString &BeanMapper::lastError()
{
    return mp_SqlOperator->lastError();
}

const QString BeanMapper::lastQuerySql()
{
    return mp_SqlOperator->lastQuerySql();
}

bool BeanMapper::__hasBeanTable(const QMetaObject &metaObj)
{
    return mp_SqlOperator->isExistTable(metaObj.className());
}

void BeanMapper::__makeTable(const QMetaObject & metaObj)
{
    QString tabName = metaObj.className();

    int propertyCount = metaObj.propertyCount();

    QList<QString> pks;
    QHash<QString,QString> tabInfo;
    for(int i = 0 ; i < propertyCount ; i++)
    {

        QMetaProperty p = metaObj.property(i);
        if(memcmp( p.name() ,"objectName",10) ==0)
        {
            continue;
        }
        QString colProperty = typeMapper[p.typeName()];
        IS_NOT_NULL(p)?colProperty.append(" NOT NULL"):colProperty;
        IS_ONLY_VAL(p)?colProperty.append(" UNIQUE"):colProperty;

        if( IS_PRIMARY_KEY(p))
        {
            QString key = p.name();
            IS_AUTO_UP(p)?key.append(" AUTOINCREMENT"):key;
            pks.append(key);

        }
        tabInfo.insert(p.name(),colProperty);
    }

    mp_SqlOperator->createTable(tabName,tabInfo,pks);
}

bool BeanMapper::__select_opt(const QString &tableName, const QList<QString> &fields, QList<QVariantList> &data, const QHash<QString, QVariant> &where)
{
    if(where.size() ==0)
    {
        return  mp_SqlOperator->selectData(tableName,fields,data);
    }
    else
    {
        return mp_SqlOperator->selectData(tableName,fields,where,data);
    }
}



bool BeanMapper::__metaToSelectMapper(const QMetaObject &metaObj , QList<QString> &selectMapper, bool autoUp)
{
    selectMapper.clear();
    int propertyCount = metaObj.propertyCount() ;
    for(int i = 0 ; i < propertyCount ;i++)
    {

        QMetaProperty p = metaObj.property(i);
        if(memcmp( p.name() ,"objectName",10) ==0)
        {
            continue;
        }
        if(autoUp && IS_AUTO_UP(p))
        {
            continue;
        }
        selectMapper.append(QString(p.name()));
    }
    return true;
}

bool BeanMapper::__mapperToObject(QObject *obj, const QList<QString> & fild,const QVariantList &values)
{
    if(fild.size() != values.size())
    {
        qDebug()<<"数据错误";
        return false;
    }
    for (int i = 0; i < fild.size(); ++i) {
        obj->setProperty(fild.at(i).toStdString().c_str(),values.at(i));
    }
    return true;
}

bool BeanMapper::__insert(const QMetaObject &metaObj, const QObject *obj)
{
    QList<QString> fild;
    __metaToSelectMapper(metaObj,fild,true);
    QVariantList values ;

    for(int i = 0 ; i < fild.size() ; i++)
    {
        values.append( obj->property(fild[i].toStdString().c_str()));
    }
    return mp_SqlOperator->insertRowData(metaObj.className(),fild,values);
}

bool BeanMapper::__insert(const QMetaObject &metaObj, const QList<const QObject*> &objs)
{
    bool recv = true;
    bool hasTransactions = !mp_SqlOperator->hasTransactions();
    if(hasTransactions )
    {
        mp_SqlOperator->transaction();
    }
    QList<QString> fild;
    __metaToSelectMapper(metaObj,fild,true);
    QList<QVariantList> valuesList;
    QList<const QObject *>::const_iterator iter = objs.begin();
    int count = 0;
    while (iter != objs.end()) {
        QVariantList values ;
        for(int i = 0 ; i < fild.size() ; i++)
        {
            values.append( (*iter)->property(fild[i].toStdString().c_str()));
        }

        valuesList.append(values);

        if(count >=100)
        {
            recv = mp_SqlOperator->insertRowsData(metaObj.className(),fild,valuesList) && recv;
            valuesList.clear();
            count =0;
        }
        count++;
        iter++;
    }
    if(valuesList.size()>0)
    {
        recv = mp_SqlOperator->insertRowsData(metaObj.className(),fild,valuesList) && recv;
    }
    if(hasTransactions)
    {
        recv = mp_SqlOperator->commit();
    }

    return recv;

}

bool BeanMapper::__selectColnum(const QMetaObject &metaObject, const QString &colName, QList<QVariant> &selectData)
{

    if(metaObject.indexOfProperty(colName.toStdString().c_str())<0)
    {
        return false;
    }
    QList<QVariantList> veriantList;
    mp_SqlOperator->selectData(metaObject.className(),{colName},veriantList);
    foreach (const QVariantList& data, veriantList) {
        if(data.size()>0)
        {
            selectData.append(data[0]) ;
        }

    }

    return true;
}

bool BeanMapper::__queryIdPropertyName(const QMetaObject &metaObj,QString& where)
{
    int propertyCount = metaObj.propertyCount() ;
    for(int i = 0 ; i < propertyCount ;i++)
    {

        QMetaProperty p = metaObj.property(i);
        if(memcmp( p.name() ,"objectName",10) ==0)
        {
            continue;
        }
        if(IS_PRIMARY_KEY(p))
        {
            where = QString(p.name());
        }
    }
    return (where.size()!=0);
}

bool BeanMapper::__update(const QMetaObject &metaObj, const QObject *obj, const QHash<QString, QVariant> &where)
{
    int propertyCount = metaObj.propertyCount() ;
    QHash<QString, QVariant> data;
    for(int i = 0 ; i < propertyCount ;i++)
    {

        QMetaProperty p = metaObj.property(i);
        if(memcmp( p.name() ,"objectName",10) ==0)
        {
            continue;
        }
        if(IS_PRIMARY_KEY(p))
        {
            continue;
        }
        data.insert(p.name(),obj->property(p.name()));

    }

    return  mp_SqlOperator->updateData(metaObj.className(),data,where);
}

bool BeanMapper::__deleteRow(const QMetaObject &metaObj, const QHash<QString, QVariant> &where)
{
    return mp_SqlOperator->deleteData(metaObj.className(),where);
}







void argsToStrValHash(const QHash<QString, QVariant> &data)
{

}
